package com.system.demo.service.comment.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.system.demo.commonService.RedisService;
import com.system.demo.entity.comment.*;
import com.system.demo.entity.comment.Comments;
import com.system.demo.mapper.UserMapper;
import com.system.demo.mapper.comment.CommentMapper;
import com.system.demo.mapper.comment.ReplyCommentMapper;
import com.system.demo.service.comment.CommentService;
import com.system.demo.tool.ResponseResult;
import io.lettuce.core.ScriptOutputType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.hutool.core.date.DateUtil.formatLocalDateTime;
import static com.system.demo.service.constant.CommentConstant.*;


@Service
public class CommentServiceImpl implements CommentService {

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private ReplyCommentMapper replyCommentMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private UserMapper userMapper;


    @Override
    public ResponseResult<?> addComment(CommentsDTO commentsDTO) {
        //先判断请求人是否为当前登录用户
        if(!commentsDTO.getFromId().equals(StpUtil.getLoginId().toString())){
            return ResponseResult.Unauthorized("当前uid尚未登录");
        }

        Comments comments = new Comments();
        BeanUtils.copyProperties(commentsDTO, comments);
        comments.setDate(LocalDateTime.now());
        if(commentsDTO.getType() == COMMENT_TYPE_ADMIN){
            comments.setIsCheck(ADMIN_IS_NOT_CHECK);
        }
        int insert = commentMapper.insert(comments);
        if(!(insert >0)){
            return ResponseResult.InternalServerError("评论发布失败，请重试");
        }

        return ResponseResult.success("发布评论成功");
    }

    @Override
    public ResponseResult<?> getComments(Integer isAll, Integer type,Integer current, Integer size) {
        String uid = StpUtil.getLoginId().toString();
        Page<Comments> commentsPage = new Page<>(current, size);
        LambdaQueryWrapper<Comments> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Comments::getDate);

        IPage<Comments> page;
        if (isAll == RETURN_ALL_COMMENTS) {
            //公共频道(type为0)  所有留言(不加uid判断)
            queryWrapper.eq(Comments::getType, COMMENT_TYPE_PUBLIC);
        } else if (isAll == RETURN_MYSELF_COMMENTS) {
            //返回个人留言 设置uid query
            queryWrapper.eq(Comments::getFromId, uid);

            if(type == COMMENT_TYPE_PUBLIC){
                //公共频道 的 个人留言
                queryWrapper.eq(Comments::getType,COMMENT_TYPE_PUBLIC );

            }else if(type == COMMENT_TYPE_ADMIN){
                //返回 系统留言
                queryWrapper.eq(Comments::getType,COMMENT_TYPE_ADMIN);
            }else{
                return ResponseResult.BadRequest("type不符合要求");
            }

        } else {
            return ResponseResult.BadRequest("isAll不符合要求");
        }
        page = commentMapper.selectPage(commentsPage, queryWrapper);
        long totalCount = page.getTotal();  // 获取总评论数
        List<CommentVO> commentVOS = processCommentsWithReplies(page.getRecords());

        return ResponseResult.success("获取留言成功", totalCount, commentVOS);
    }

    @Override
    @Transactional
    public ResponseResult<?> deleteComments(Integer commentId) {
        // 检查该评论是否为当前uid用户的
        String uid = StpUtil.getLoginId().toString();

        Comments comments = commentMapper.selectById(commentId);

        if (comments == null) {
            return ResponseResult.BadRequest("无效的评论id");
        }

        if (!comments.getFromId().equals(uid)) {
            return ResponseResult.Unauthorized("您无权删除他人的评论");
        }

        // 删除关联的回复
        LambdaQueryWrapper<ReplyComment> replyQueryWrapper = new LambdaQueryWrapper<>();
        replyQueryWrapper.eq(ReplyComment::getCommentId, commentId);

        // 尝试删除数据库中的回复
        if (!(replyCommentMapper.delete(replyQueryWrapper) >= 0)) {
            return ResponseResult.InternalServerError("删除回复失败，请重试");
        }

        // 尝试删除数据库中的评论
        if (!(commentMapper.deleteById(commentId) > 0)) {
            return ResponseResult.InternalServerError("删除评论失败，请重试");
        }

        // 删除Redis中缓存的点赞数据
        String likeKey = "commentLike:" + commentId;
        redisService.deleteTokenKey(likeKey);  // 假设你有一个删除key的方法

        String cacheKey = "rankingList:comments"; // Redis 缓存键名
        redisService.deleteTokenKey(cacheKey);

        return ResponseResult.success("删除成功");
    }

    @Override
    public ResponseResult<?> likeComments(Integer commentId) {
        // 检查留言是否存在
        String uid = StpUtil.getLoginId().toString();
        Comments comments = commentMapper.selectById(commentId);
        if (comments == null) {
            return ResponseResult.BadRequest("无此留言");
        }
        if(comments.getType() == COMMENT_TYPE_ADMIN){
            return ResponseResult.success("您要的答案正在路上...",1,1);
        }
        // 为留言创建键名
        String likeKey = "commentLike:" + commentId;
        // 创建 点赞榜 的键名
        String rankKey = "commentLikesRank";

        // 查看该用户是否点过赞
        boolean isLiked = redisService.sIsMember(likeKey, uid);

        if (isLiked) {
            // 用户已点赞过 取消点赞
            redisService.sRem(likeKey, uid);
            Long count = redisService.incrementZSetLikeCount(rankKey, commentId.toString(), -1);// 减少评分
            return ResponseResult.success("取消点赞成功",0, count);
        } else {
            // 用户还未点赞  添加点赞
            redisService.sAdd(likeKey, uid);
            Long count = redisService.incrementZSetLikeCount(rankKey, commentId.toString(), 1);// 增加评分
            return ResponseResult.success("点赞成功",1, count);
        }
    }

    @Override
    @Transactional
    public ResponseResult<?> deleteCommentsByAdmin(Integer type, Integer id) {

        //type如果为0 代表留言 type为1代表评论
        if(type == REMOVE_TYPE_LIUYAN){
            // 批量查询评论以验证存在性并获取相关信息
            Comments commentsToDelete = commentMapper.selectById(id);
            if (commentsToDelete == null) {
                return ResponseResult.BadRequest("无效的留言id");
            }

            // 删除关联的回复
            LambdaQueryWrapper<ReplyComment> replyQueryWrapper = new LambdaQueryWrapper<>();
            replyQueryWrapper.in(ReplyComment::getCommentId, id);

            List<ReplyComment> replyComments = replyCommentMapper.selectList(replyQueryWrapper);
            if(!replyComments.isEmpty()){
                // 尝试删除数据库中的回复
                int deletedReplyCount = replyCommentMapper.delete(replyQueryWrapper);

                if (!(deletedReplyCount > 0)) { // 如果有任何错误发生
                    return ResponseResult.InternalServerError("删除回复失败，请重试");
                }
            }

            // 批量删除评论
            int deletedCount = commentMapper.deleteById(id);

            // 检查删除是否成功
            if (!(deletedCount > 0)) {
                return ResponseResult.InternalServerError("留言删除失败，请重试");
            }
            String key = "commentLike:" + id;
            redisService.deleteTokenKey(key);  // 删除Redis key

            String cacheKey = "rankingList:comments"; // Redis 缓存键名
            redisService.deleteTokenKey(cacheKey);
            return ResponseResult.success("删除留言成功");
        }else if(type == REMOVE_TYPE_PINGLUN){
            int i = replyCommentMapper.deleteById(id);
            if(!(i > 0)){
                return ResponseResult.InternalServerError("删除回复失败，请重试");
            }
            return ResponseResult.success("删除回复成功");
        }else{
            return ResponseResult.BadRequest("请检查type参数");
        }
    }

    @Override
    public ResponseResult<?> addReply(ReplyDTO replyDTO) {
        ReplyComment replyComment = new ReplyComment();
        BeanUtils.copyProperties(replyDTO, replyComment);
        replyComment.setDate(LocalDateTime.now());
        if(!(replyCommentMapper.insert(replyComment) > 0)){
            return ResponseResult.InternalServerError("回复失败，请重试");
        }
        return ResponseResult.success("回复成功");
    }

    @Override
    public ResponseResult<?> removeReply(Integer replyId) {
        String uid = StpUtil.getLoginId().toString();
        ReplyComment replyComment = replyCommentMapper.selectById(replyId);
        if(replyComment == null){
            return ResponseResult.BadRequest("未查找到该回复");
        }
        if(!replyComment.getFromId().equals(uid)){
            return ResponseResult.Unauthorized("您无权删除他人的评论");
        }

        if(!(replyCommentMapper.deleteById(replyId) > 0)){
            return ResponseResult.InternalServerError("服务器内部错误，请重试");
        }

        return ResponseResult.success("删除评论成功");
    }

    @Override
    public ResponseResult<?> getInvolved(Integer current, Integer size) {
        String uid = StpUtil.getLoginId().toString();
        List<Integer> commentIds = replyCommentMapper.selectCommentIdsByUserId(uid);

        if (commentIds.isEmpty()) {
            return ResponseResult.success("未找到该用户参与的任何留言");
        }

        Page<Comments> page = new Page<>(current, size);
        LambdaQueryWrapper<Comments> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Comments::getId, commentIds)
                .eq(Comments::getType, COMMENT_TYPE_PUBLIC)
                .orderByDesc(Comments::getDate);

        IPage<Comments> commentPage = commentMapper.selectPage(page, queryWrapper);
        long totalCount = commentPage.getTotal();  // 获取总评论数
        List<CommentVO> commentVOS = processCommentsWithReplies(commentPage.getRecords());

        return ResponseResult.success("查询成功", totalCount, commentVOS);
    }

    @Override
    public ResponseResult<?> getRankingList() {
        // 点赞榜 键名
        String rankKey = "commentLikesRank";
        String cacheKey = "rankingList:comments"; // Redis 缓存键名

        // 定义排行榜大小
        int topN = 5; // 返回前五的留言

        try {
            // 尝试从 Redis 获取缓存数据
            List<Map<String, Object>> cachedRanking = redisService.getRankingListFromCache(cacheKey);
            if (cachedRanking != null && !cachedRanking.isEmpty()) {
                return ResponseResult.success("从redis获取排行榜成功", cachedRanking);
            }

            // 如果 Redis 中没有缓存，从 MySQL 查询并更新 Redis 缓存
            List<RankingItem> rankingItems = redisService.getTopNFromZSet(rankKey, topN);
            if (rankingItems == null || rankingItems.isEmpty()) {
                return ResponseResult.success("排行榜为空", Collections.emptyList());
            }
            // 提取所有留言 ID
            List<Integer> commentIds = rankingItems.stream()
                    .map(RankingItem::getCommentId)
                    .collect(Collectors.toList());

            // 根据留言 ID 列表批量查询留言详情
            List<Comments> comments = commentMapper.selectBatchIds(commentIds);

            // 提取所有唯一的留言 from_id 并转换为 List
            List<String> userIds = comments.stream()
                    .map(Comments::getFromId) // 假设 Comments 类中有 getFromId 方法获取 from_id
                    .distinct() // 确保唯一性，等同于 collect(Collectors.toSet())
                    .collect(Collectors.toList());

            System.out.println("排行榜中的所有uid"+ userIds);

            // 批量查询用户头像
            List<UserAvatarDTO> avatarList = userMapper.getUserAvatarsByIds(userIds);

            // 构造 Map<String, String>
            Map<String, String> userAvatarsByIds = avatarList.stream()
                    .collect(Collectors.toMap(UserAvatarDTO::getUid, UserAvatarDTO::getAvatar));


            // 将留言详情与点赞数量关联起来
            Map<Integer, Long> likeCountMap = rankingItems.stream()
                    .collect(Collectors.toMap(RankingItem::getCommentId, RankingItem::getLikeCount));

            // 构建最终返回的数据结构
            List<Map<String, Object>> result = comments.stream()
                    .filter(comment -> likeCountMap.containsKey(comment.getId())) // 只保留存在于排行榜中的评论
                    .map(comment -> {
                        Map<String, Object> item = new HashMap<>();
                        item.put("id", comment.getId());
                        item.put("content", comment.getContent());
                        item.put("author", comment.getFromName());
                        item.put("likeCount", likeCountMap.get(comment.getId()));
                        item.put("date", formatLocalDateTime(comment.getDate()));
                        item.put("avatar", userAvatarsByIds.get(comment.getFromId()));
                        return item;
                    })
                    .collect(Collectors.toList());

            // 更新 Redis 缓存，并设置一天的过期时间
            redisService.cacheRankingList(cacheKey, result, 1, TimeUnit.DAYS);

            return ResponseResult.success("获取排行榜成功", result);
        } catch (Exception e) {
            // 捕获并处理可能的异常
            return ResponseResult.InternalServerError("获取排行榜失败：" + e.getMessage());
        }
    }

    @Override
    public ResponseResult<?> getPrivateMessage(Integer isCheck, Integer current, Integer size) {
        //管理员查询 私聊 的留言 isCheck 0代表未回复  1代表已回复
        // 创建分页对象
        Page<Comments> page = new Page<>(current, size);
        LambdaQueryWrapper<Comments> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Comments::getDate);
        //查询未回复的系统留言
        if(isCheck == ADMIN_IS_NOT_CHECK){
            Page<Comments> notCheckComments = commentMapper.selectPage(page, queryWrapper.eq(Comments::getIsCheck, ADMIN_IS_NOT_CHECK));
            List<CommentVO> commentVOS = processCommentsWithReplies(notCheckComments.getRecords());
            return ResponseResult.success("查询未回复留言成功", notCheckComments.getTotal(), commentVOS);
        } else if (isCheck == ADMIN_IS_CHECK) {
            Page<Comments> checkComments = commentMapper.selectPage(page, queryWrapper.eq(Comments::getIsCheck, ADMIN_IS_CHECK));
            List<CommentVO> commentVOS = processCommentsWithReplies(checkComments.getRecords());
            return ResponseResult.success("查询已回复留言成功", checkComments.getTotal(), commentVOS);
        }else{
            return ResponseResult.BadRequest("无效的isCheck参数");
        }
    }

    @Override
    @Transactional
    public ResponseResult<?> addReplyByAdmin(ReplyDTO replyDTO) {
        //这是管理员对于 系统留言的回复
        //存入回复
        ReplyComment replyComment = new ReplyComment();
        BeanUtils.copyProperties(replyDTO, replyComment);
        replyComment.setDate(LocalDateTime.now());
        int insert = replyCommentMapper.insert(replyComment);
        if(!(insert > 0)){
            return ResponseResult.InternalServerError("内部服务器错误，请重试");
        }
        Integer commentId = replyDTO.getCommentId();
        // 更新 comments 表中的 is_check 字段为 1，代表已经回复
        int i = commentMapper.updateIsCheck(commentId);
        if(! (i > 0)){
            return ResponseResult.InternalServerError("更新留言状态失败，请重试");
        }
        // 返回成功响应
        return ResponseResult.success("回复成功并已更新留言状态");
    }

    private List<CommentVO> processCommentsWithReplies(List<Comments> comments) {
        // 处理留言，转换为VO
        List<CommentVO> commentVOS = processComments(comments);

        // 对每个评论进行处理，加载其对应的回复
        for (CommentVO commentVO : commentVOS) {
            LambdaQueryWrapper<ReplyComment> replyQueryWrapper = new LambdaQueryWrapper<>();
            replyQueryWrapper.eq(ReplyComment::getCommentId, commentVO.getId())
                    .orderByAsc(ReplyComment::getDate); // 按回复时间升序

            List<ReplyComment> replies = replyCommentMapper.selectList(replyQueryWrapper);
            List<ReplyCommentVO> replyCommentVOS = formatReplies(replies);
            commentVO.setReply(replyCommentVOS);
        }

        return commentVOS;
    }

    // 这里假设processComments是一个已有的方法，用于将Comments列表转换为CommentVO列表。其实就是格式化日期 并从redis中查找点赞数
    private List<CommentVO> processComments(List<Comments> comments) {
        // 构建 Redis key 列表并批量获取点赞数
        List<String> likeKeys = comments.stream()
                .map(comment -> "commentLike:" + comment.getId())
                .collect(Collectors.toList());

        Map<String, Long> likeCounts = redisService.getLikeCounts(likeKeys);

        List<CommentVO> commentVOS = new ArrayList<>();
        for (Comments comment : comments) {
            CommentVO commentVO = new CommentVO();
            BeanUtils.copyProperties(comment, commentVO); // 使用Spring的Bean工具类复制属性

            // 设置头像和日期格式化
            commentVO.setFromAvatar(userMapper.findAvatarByUid(comment.getFromId()));
            commentVO.setDate(formatLocalDateTime(comment.getDate()));

            // 设置点赞数
            String likeKey = "commentLike:" + comment.getId();
            Long likeCount = likeCounts.getOrDefault(likeKey, 0L);
            commentVO.setLikeNum(likeCount);

            commentVOS.add(commentVO);
        }
        return commentVOS;
    }

    // 定义一个辅助方法来处理日期格式化
    private List<ReplyCommentVO> formatReplies(List<ReplyComment> replies) {
        List<ReplyCommentVO> replyCommentVOS = new ArrayList<>();
        for (ReplyComment reply : replies) {
            ReplyCommentVO replyCommentVO = new ReplyCommentVO();
            BeanUtils.copyProperties(reply, replyCommentVO);
            replyCommentVO.setDate(formatLocalDateTime(reply.getDate()));
            replyCommentVOS.add(replyCommentVO);
        }
        return replyCommentVOS;
    }

}
